package tesis.common.security.filter;

import tesis.common.security.exception.EnSesionException;
import tesis.common.security.service.AbstractTokenBasedRememberMeServices;
import tesis.common.utils.ControllerUtil;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

/**
 * Clase que actua como cortafuegos para todos los accesos no autorizados al
 * sistema. Garantiza que para ejecutar las operaciones del sistema el usuario
 * haya pasado por la ventana de login.
 *
 * @author ACOTRINA @modificado Sergio Buchelli @modificado diego.gil
 */
public class SecurityFilter extends GenericFilterBean implements ApplicationEventPublisherAware {

    /**
     * Objeto con los datos de configuracion del filtro.
     */
    private static final Logger LOG = LoggerFactory.getLogger(SecurityFilter.class);
    private ApplicationEventPublisher eventPublisher;
    private AuthenticationManager authenticationManager;
    private String errorDefault = "/error/errorLogin.html";
    private String errorEnSesion = "/error/enSesion.html";
    private AbstractTokenBasedRememberMeServices rememberMeServices;

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(authenticationManager, "authenticationManager must be specified");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        LOG.debug("<<-------------------------- SecurityFilter - doFilter");
        HttpServletRequest request = (HttpServletRequest) req;
        request.setCharacterEncoding("UTF-8");
        HttpServletResponse response = (HttpServletResponse) res;
        String uri = request.getRequestURI();

        if (!uri.contains("qasFileDownload")) {
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "0");
            response.setCharacterEncoding("UTF-8");
        }
//        if (loginService.saltarFiltro(request)) {
//           log.debug("Salto filtro");
//           chain.doFilter(request, response);
//           return;
//        }
        /*
         * if(uri.endsWith("login.action")||uri.endsWith("login.action/")||uri.endsWith("siged")||uri.endsWith("siged/")){
         * request.getRequestDispatcher("/error/finSesion.html").forward(request,response);
         * return; }
         */
//        HttpSession session = request.getSession(false);
//        if (session != null){
//            String username = ControllerUtil.obtainSessionAttribute(session, "j_username", String.class);
//            if (username != null) {
//                UsuarioSeguridad usuario = ControllerUtil.obtainSessionAttribute(session, Constantes.SESSION_USUARIO,UsuarioSeguridad.class);
//                String usuarioSession = (usuario == null) ? null : usuario.getUsuario();
//                if (usuarioSession != null) {
//                    if (!usuarioSession.equalsIgnoreCase(username)) {
//                        log.warn("El usuario "+username+" esta intentando iniciar sesion, pero el usuario "+usuarioSession+" ya esta en sesion.");
//                        request.getRequestDispatcher("/error/enSesion.html").forward(request,response);
//                        return;
//                    }
//                }
//            }
//        }

        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            Authentication rememberMeAuth;
            try {
                rememberMeAuth = rememberMeServices.customAutoLogin(request, response);
            } catch (EnSesionException ex) {
                request.getRequestDispatcher(errorEnSesion).forward(request, response);
                return;
            } catch (Exception ex) {
                request.getRequestDispatcher(errorDefault).forward(request, response);
                return;
            }
            LOG.debug("rememberMeAuth: " + rememberMeAuth);
            if (rememberMeAuth != null) {
                // Attempt authenticaton via AuthenticationManager
                try {
                    rememberMeAuth = authenticationManager.authenticate(rememberMeAuth);
                    // Store to SecurityContextHolder
                    SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
                    LOG.debug("rememberMeAuth set to Context");
                    onSuccessfulAuthentication(request, response, rememberMeAuth);
                    if (logger.isDebugEnabled()) {
                        logger.debug("SecurityContextHolder populated with remember-me token: '"
                                + SecurityContextHolder.getContext().getAuthentication() + "'");
                    }
                    // Fire event
                    if (this.eventPublisher != null) {
                        eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
                                SecurityContextHolder.getContext().getAuthentication(), this.getClass()));
                    }
                } catch (AuthenticationException authenticationException) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("SecurityContextHolder not populated with remember-me token, as "
                                + "AuthenticationManager rejected Authentication returned by RememberMeServices: '"
                                + rememberMeAuth + "'; invalidating remember-me token", authenticationException);
                    }
                    rememberMeServices.loginFail(request, response);
                    onUnsuccessfulAuthentication(request, response, authenticationException);
                }
            }
            chain.doFilter(request, response);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("SecurityContextHolder not populated with remember-me token, as it already contained: '"
                        + SecurityContextHolder.getContext().getAuthentication() + "'");
            }
            LOG.debug("request.getRequestURI():" + request.getRequestURI());
            if (request.getRequestURI().contains("login.action")) {
                response.sendRedirect(ControllerUtil.obtainSigedUrlBase(request) + "inicio.action");
            }
            chain.doFilter(request, response);
        }
    }

    public AuthenticationManager getAuthenticationManager() {
        return authenticationManager;
    }

    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    public String getErrorDefault() {
        return errorDefault;
    }

    public void setErrorDefault(String errorDefault) {
        this.errorDefault = errorDefault;
    }

    public String getErrorEnSesion() {
        return errorEnSesion;
    }

    public void setErrorEnSesion(String errorEnSesion) {
        this.errorEnSesion = errorEnSesion;
    }

    public ApplicationEventPublisher getEventPublisher() {
        return eventPublisher;
    }

    public void setEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public AbstractTokenBasedRememberMeServices getRememberMeServices() {
        return rememberMeServices;
    }

    public void setRememberMeServices(AbstractTokenBasedRememberMeServices rememberMeServices) {
        this.rememberMeServices = rememberMeServices;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        eventPublisher = applicationEventPublisher;
    }

    protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication rememberMeAuth) {
        LOG.debug("onSuccessfulAuthentication");
    }

    protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) {
        LOG.debug("onUnsuccessfulAuthentication");
    }
}